iT邦幫忙

2024 iThome 鐵人賽

DAY 6
1
Kubernetes

都什麼年代了,還在學 Kubernetes系列 第 6

學 Kubernetes 的第六天 - 部署你的第一個應用程式 (1) - Application & Image

  • 分享至 

  • xImage
  •  

概述

我不打算一開始就深入研究 Kubernetes 的各個元件或是資源。就像看科幻小說,如果一上來就直接看背景設定肯定是最無趣的讀法。

我會花幾天時間帶大家使用 Kubernetes 部署你的第一個應用程式,過程中我們會實作:

  1. 手搓一個簡單的 Web API 應用,並打包成 Docker Image 推送到 Container Registry。
  2. 在 K8s Pod 部署該 Web API,使其可以從外部訪問。
  3. 將 Web API 改用 Deployment 部署,提高應用的可用性和承載能力。

在這系列的實作中,我將介紹 PodServiceDeployment 等 Kubernetes 對象的基本概念及其相關特性,確保實作過程的順暢。更詳細的討論將在後續的主題章節中展開。

實作

我們今天的目標是完成 Web API打包 Image上傳到容器倉庫 Docker Hub (Container Registry)。示意圖如下:

https://ithelp.ithome.com.tw/upload/images/20240920/201682128gk1T6vH5T.png

開始之前

  1. 我們要使用 golang 撰寫 Web API,需要事先安裝 golang 套件。安裝方法可以參考 Download and install - The Go Programming Language
  2. 我們會使用 Docker 官方的容器倉庫 Docker Hub,事先註冊好帳號。

提醒:

如果想要直接在 WSL - Ubuntu 內安裝 golang,可以使用以下指令:

sudo apt install golang-go
  • 檢查 go 版本
go version
---
go version go1.18.1 linux/amd64

撰寫 Web API

  • 在工作目錄中創建 foo 資料夾,並進入其中。這將會是我們應用的根目錄。

檔案: main.go

package main

import (
	"net/http"
	"os"
	"time"

	"github.com/gin-gonic/gin"
)

func main() {
	hostname, _ := os.Hostname()
	started := time.Now()

	r := gin.Default()
	r.GET("/", func(c *gin.Context) {
		c.String(http.StatusOK, "foo")

	})

	r.GET("/hostname", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"hostname": hostname,
		})

	})

	r.GET("/healthy", func(c *gin.Context) {
		c.Status(http.StatusOK)
	})

	r.GET("/healthy_test", func(c *gin.Context) {
		duration := time.Since(started)
		if duration.Seconds() > 30 {
			c.Status(http.StatusServiceUnavailable)
		} else {
			c.Status(http.StatusOK)
		}
	})
	r.Run()
}

上述檔案使用 golanggin package 撰寫的 Web API,提供以下端點:

  • /: 返回固定訊息。
  • /hostname: 返回系統主機名稱。
  • /healthy: 作為健康檢查端點,恆定返回 HTTP 200 狀態碼。
  • /healthy_test: 作為探針測試端點,啟動後 30 秒內返回 HTTP 200,之後返回 HTTP 503。

  • 將上述內容複製儲存到 foo 資料夾內,命名為 main.go

  • 初始化專案

go mod init example.com/foo
  • 執行指令來下載 gin 套件
go get -u github.com/gin-gonic/gin
  • 清理專案依賴
go mod tidy
  • 執行專案
go run main.go
---
[GIN-debug] GET    /                         --> main.main.func1 (3 handlers)
[GIN-debug] GET    /hostname                 --> main.main.func2 (3 handlers)
[GIN-debug] GET    /healthy                  --> main.main.func3 (3 handlers)
[GIN-debug] GET    /healthy_test             --> main.main.func4 (3 handlers)
[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.
Please check https://pkg.go.dev/github.com/gin-gonic/gin#readme-don-t-trust-all-proxies for details.
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on :8080
  • 測試端口
curl 0.0.0.0:8080
---
foo

建立 Docker Image

我們繼續在 foo 目錄下進行操作。

Docker 組態檔: Dockerfile

FROM golang:latest AS builder
WORKDIR /
COPY go.mod go.sum ./
RUN go mod download
COPY *.go ./
RUN CGO_ENABLED=0 GOOS=linux go build -o main

FROM alpine:latest
WORKDIR /
COPY --from=builder ./main .
EXPOSE 8080
CMD [ "./main" ]

build 用到的指令:

  • CGO 是 Go 語言用來調用 C 語言代碼的工具。默認情況下,CGO 是啟用的,這意味著構建過程中可能會依賴於系統的 C 編譯器和標準庫。在 Docker 容器中,這可能導致兼容性問題,尤其是當你從一個環境(如 macOS)構建並在另一個環境(如 Alpine Linux)運行時。因此,通過設置 CGO_ENABLED=0 禁用 CGO,可以確保構建出的二進位文件是純 Go 的,不依賴於任何 C 庫,從而提高了可攜性。

  • 設置 GOOS=linux 可以確保構建出的二進位文件是針對 Linux 操作系統的,即使構建是在其他操作系統(如 macOS 或 Windows)上進行的。這對於在 Linux 基於 Docker 容器中運行的應用程式來說是至關重要的。

  • Dockerfile 內容複製儲存到 foo 資料夾內,命名為 Dockerfile

  • 編譯為 Image

docker build -t foo .
  • 運行 Image 內容
docker run --rm -p 8080:8080 -it -d foo
  • 測試 Container 內的 Web API
curl 0.0.0.0:8080
---
foo

這樣我們就完成了應用的容器化。

推送 Image 到 Docker Hub

接下來,我們要將容器的映像檔推送到容器倉庫,下面的實作會用我自己的帳號 lofairy 作為演示,各位要操作記得換成自己的帳號。

  • 確認 Image 無誤,打正式的推送 tag
docker tag hello lofairy/foo:latest
  • 推送到 Container Registry (Docker Hub)
docker push lofairy/foo

做到這裡我們的應用就算全部完成了。下面我們來驗證 Image 是否可以正常執行。

  • 執行倉庫的容器
docker run --rm -p 8080:8080 -it -d lofairy/foo
  • 測試端口
curl 0.0.0.0:8080
---
foo

上一篇
學 Kubernetes 的第五天 - Kubernetes 瑞士刀 - kubectl
下一篇
學 Kubernetes 的第七天 - 部署你的第一個應用程式 (2) - Pod & Service
系列文
都什麼年代了,還在學 Kubernetes37
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言